package com.bangcommunity.bbframe.mlog;

import com.bangcommunity.bbframe.common.utils.id.UidUtil;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author tanghc
 * @date 18/1/25
 */
public abstract class LogContextHelper {
    static ThreadLocal<Deque<LogContext>> contextThreadLocal = new ThreadLocal<>();
    static ThreadLocal<String> txidThreadLocal = new ThreadLocal<String>() {
        @Override
        public String initialValue() {
            return UidUtil.getId();
        }
    };

    public static LogContext pushLogContextInitIfNull(String parentTxid, String mkey, String bizKey, Object[] args) {
        LogContext peekLogContext = peekLogContext();
        LogContext logContext = new LogContext();
        logContext.setStartTimeMs(System.currentTimeMillis());
        logContext.setMkey(mkey);
        logContext.setBizKey(bizKey);
        logContext.setArgs(args);
        logContext.setTxId(txidThreadLocal.get());
        if (null == peekLogContext) {
            logContext.setThreadName(Thread.currentThread().getName());
            logContext.setPtxId(parentTxid);
        } else {
            logContext.setThreadName(peekLogContext.getThreadName());
            logContext.setTxId(peekLogContext.getTxId());
            logContext.setPtxId(peekLogContext.getPtxId());
        }
        if (null == logContext.getPtxId()) {
            logContext.setPtxId(parentTxid);
        }

        push(logContext);
        return logContext;
    }

    public static Deque<LogContext> getLogContextDequeInitIfNull() {
        Deque<LogContext> logContextsDeque = contextThreadLocal.get();
        if (null == logContextsDeque) {
            logContextsDeque = new ArrayDeque<>(32);
            contextThreadLocal.set(logContextsDeque);
        }
        return logContextsDeque;
    }

    public static LogContext peekLogContext() {
        Deque<LogContext> logContextsDeque = getLogContextDequeInitIfNull();
        return logContextsDeque.peek();
    }

    public static void push(LogContext logContext) {
        Deque<LogContext> logContextsDeque = getLogContextDequeInitIfNull();
        logContextsDeque.push(logContext);
    }

    public static LogContext popSafe() {
        Deque<LogContext> logContextsDeque = getLogContextDequeInitIfNull();
        LogContext pop = null;
        try {
            pop = logContextsDeque.pop();
        } catch (Exception e) {
        }
        if (logContextsDeque.isEmpty()) {
            contextThreadLocal.remove();
        }
        return pop;
    }

}
